#!/bin/bash
#
# Copyright (C) 2016-2021 Wu Zhangjin <falcon@ruma.tech>
#

# Please don't run it manually
[ ! -d /labs -o ! -d /.git ] && echo "ERR: Please don't run this manually, do you mean tools/docker/run ?" && exit 1

# Dump environment variables
# env

# Clean up everything before running
find /var/lib/apt/lists /var/cache /var/log -type f -delete &

# NOTE: for Security, variables should be passed as environment variables
. /tools/docker/container >/dev/null

# Do some preparation
do_prepare ()
{
  get_vars MIRROR_SITE VNC_IP VNC_TOKEN

  # Configure mirror site
  if [ -n "$MIRROR_SITE" ]; then
    old=$(sed -ne "0,/^deb/s%deb .*://\([^/ ]*\)/.*%\1%p" /etc/apt/sources.list)
    [ "$old" != "$MIRROR_SITE" ] && sed -i -e "s/$old/$MIRROR_SITE/g" /etc/apt/sources.list
  fi

  # Configure network
  IFACE=$(ifconfig | sed -ne '1s/\(.*\): .*/\1/p')
  if [ "$VNC_IP" != "$DEF_VNC_IP" ]; then
    ROUTE_IP=$(route -n | sed -ne "0,/^0.0.0.0/s/^0.0.0.0 *\([^ ]*\).*/\1/p")
    ifconfig $IFACE $VNC_IP up
    _ROUTE_IP=$(route -n | sed -ne "0,/^0.0.0.0/s/^0.0.0.0 *\([^ ]*\).*/\1/p")
    [ -z "$_ROUTE_IP" ] && route add default gw $ROUTE_IP $IFACE
  else
    VNC_IP=`ifconfig $IFACE | sed -ne 's/.*inet \([0-9.]*\) .*/\1/p'`
  fi

  if [ -n "$VNC_IP" ]; then
    [ "$VNC_IP" != "$DEF_VNC_IP" ] && set_var VNC_IP
    [ -z "$VNC_TOKEN" ] && VNC_TOKEN=`echo -n $VNC_IP | tr -d '\n' | $ENCRYPT_CMD | cut -d' ' -f1 | cut -c1-$TOKEN_LENGTH` && set_var VNC_TOKEN
  fi

  do_lock
}

# Do desktop detection
do_desktop_config ()
{
  # Convert xfce to xfce4
  [ "$DESKTOP" = "xfce" ] && DESKTOP=xfce4

  # Use lxde by default, detect the other desktops one by one
  desktop=lxde
  if [ -z "$DESKTOP" -o "$DESKTOP" = "auto" ]; then
    # Left first
    for x in xfce4 cinnamon lxqt
    do
      if [ -f /usr/bin/${x}-session ]; then
        ln -sf /usr/bin/${x}-session /usr/bin/lxsession
	desktop=$x
	break
      fi
    done
  elif [ "$DESKTOP" != "$desktop" ]; then
    if [ -f /usr/bin/${DESKTOP}-session ]; then
      ln -sf /usr/bin/${DESKTOP}-session /usr/bin/lxsession
      desktop=$DESKTOP
    fi
  fi
}

# Configure pass
do_pass_config ()
{
  # UNIX PASS
  echo "$UNIX_USER:$UNIX_PWD" | chpasswd

  [ -z "$UNIX_IDENTIFY" ] && UNIX_IDENTIFY=1
  # Forbit unix user login(no identify) by locking it, and unlock it for login available(identify)
  [ $UNIX_IDENTIFY -eq 0 ] && passwd -l $UNIX_USER
  [ $UNIX_IDENTIFY -eq 1 ] && passwd -u $UNIX_USER
}

# Configure vnc
do_vnc_config ()
{
  which x11vnc >/dev/null 2>&1
  [ $? -ne 0 ] && return 0

  VNC_PWD_FILE=$HOME/.vnc/passwdfile
  [ ! -d $HOME/.vnc ] && mkdir -p $HOME/.vnc
  echo $VNC_PWD > $VNC_PWD_FILE
  echo __BEGIN_VIEWONLY__ >> $VNC_PWD_FILE
  echo $VNC_PWD_VIEWONLY >> $VNC_PWD_FILE

  get_vars PWD_LENGTH PWD_TOTAL
  if [ $PWD_TOTAL -gt 0 ]; then
    PWGEN_OPTS="-B -s -n -v $PWD_LENGTH $PWD_TOTAL"
    pwgen $PWGEN_OPTS | tr ' ' '\n' >> $VNC_PWD_FILE
  fi
  chmod o-rwx $VNC_PWD_FILE

  # Update user setting
  X11VNC_SUPERVISORD_CONF=/etc/supervisor/conf.d/x11vnc.conf
  if [ "$UNIX_USER" != "$DEF_UNIX_USER" ]; then
    sed -i -e "s%$DEF_HOME%$HOME%g" $X11VNC_SUPERVISORD_CONF
    sed -i -e "s%user=$DEF_UNIX_USER%user=$UNIX_USER%g" $X11VNC_SUPERVISORD_CONF
  fi

  # Disable the VNC login password
  [ -z "$VNC_IDENTIFY" ] && VNC_IDENTIFY=1
  if [ $VNC_IDENTIFY -eq 0 ]; then
    get_var HOST_NAME
    [ "x$HOST_NAME" = "xlocalhost" ] && sed -i -e "s% -usepw$%-nopw%g" $X11VNC_SUPERVISORD_CONF
  fi
}

# Sync uid
do_uid_sync ()
{
  FILES_TO_SYN_PERM="$LAB_UNIX_PWD $LAB_VNC_PWD $LAB_VNC_PWD_VIEWONLY $LAB_UNIX_UID $LAB_UNIX_USER $LAB_VNC_IP $LAB_VNC_TOKEN"
  for f in $FILES_TO_SYN_PERM
  do
    [ ! -f $f ] && continue
    sudo chown $UNIX_USER:$UNIX_USER $f
    sudo chmod a+w $f
  done
}

# Configure user and pass
do_user_config ()
{
  # Create password, ENV > CONF > PWGEN
  do_unlock

  get_vars UNIX_PWD VNC_PWD VNC_PWD_VIEWONLY PWD_LENGTH PWD_TOTAL
  PWGEN_OPTS="-B -s -n -v $PWD_LENGTH 1"
  [ -z "$UNIX_PWD" ] && UNIX_PWD=`pwgen $PWGEN_OPTS | tr '[A-Z]' '[a-z]'`
  [ -z "$VNC_PWD" ] && VNC_PWD=`pwgen $PWGEN_OPTS | tr '[A-Z]' '[a-z]'`
  [ -z "$VNC_PWD_VIEWONLY" ] && VNC_PWD_VIEWONLY=`pwgen $PWGEN_OPTS | tr '[A-Z]' '[a-z]'`
  set_vars UNIX_PWD VNC_PWD VNC_PWD_VIEWONLY

  # Sync UID between host and container
  do_uid_sync &

  do_lock

  # Don't touch me: otherwise, need to modify tools/docker/run
  echo "User: $UNIX_USER ,Password: $UNIX_PWD ,VNC Password: $VNC_PWD ,Viewonly Password: $VNC_PWD_VIEWONLY"

  # set password
  do_pass_config &
}

# Configure owner
do_owner_config ()
{
  volumes="$GIT_WORKDIR $LAB_WORKDIR $TOOL_WORKDIR $CONFIG_WORKDIR"
  UNIX_GID=`id -g $UNIX_USER`
  for v in $volumes
  do
    user=$(stat -c '%U' $v)
    if [ "$user" != "$UNIX_USER" ]; then
      uid=$(stat -c '%u' $v)
      if [ "$uid" != "$UNIX_UID" ]; then
        (eval nohup chown $UNIX_UID:$UNIX_GID -R $v >/dev/null 2>&1 &)>/dev/null 2>&1
      fi
    fi
  done
}

# Configure loop
do_loop_config ()
{
  # create potential missing loop devices for some systems
  if [ ! -b /dev/loop7 ]; then
    max_loop=$(cat /proc/cmdline | tr " " "\n" | grep max_loop | cut -d '=' -f2)
    [ -z "$max_loop" ] && max_loop=7
    for i in `seq 0 $max_loop`
    do
      mknod /dev/loop$i b 7 $i &
    done
  fi
}

# Startup scripts
run_startup_scripts ()
{
  # Run Lab specific tasks
  [ -x $LAB_CONTAINER_RUN ] && UNIX_USER=$UNIX_USER $LAB_CONTAINER_RUN &

  for f in /etc/startup.aux/*.sh
  do
    [ ! -x $f ] && chmod a+x $f
    $f
  done
}

# Create home
do_home_create ()
{
  [ $SUDO_IDENTIFY -ge 1 ] && UNIX_USER_GROUPS="--groups adm,sudo,audio"
  [ $SUDO_IDENTIFY -eq 0 ] && UNIX_USER_GROUPS=""

  # The old one should be removed before create a new one, but reserve the saved directory
  id -u $UNIX_USER &>/dev/null && userdel -f $UNIX_USER

  useradd --uid $UNIX_UID --create-home --shell /bin/bash --user-group $UNIX_USER_GROUPS $UNIX_USER

  # Make sure the local python install path added to PATH, see ~/.profile from tools/system/etc/bash.bashrc
  mkdir -p $HOME/.local/bin
}

# Hack sudo
do_sudo_hack ()
{
  [ -z "$SUDO_IDENTIFY" ] && SUDO_IDENTIFY=2

  DEF_SYSTEM_SUDOERS_USER=/etc/sudoers.d/$DEF_UNIX_USER
  SYSTEM_SUDOERS_USER=/etc/sudoers.d/$UNIX_USER
  [ $SUDO_IDENTIFY -eq 2 ] && echo "$UNIX_USER ALL=(ALL) NOPASSWD: ALL" > $SYSTEM_SUDOERS_USER \
			&& chmod 440 $SYSTEM_SUDOERS_USER

  [ -f "$DEF_SYSTEM_SUDOERS_USER" -a "$LAB_SECURITY" != "0" ] \
    && mv $DEF_SYSTEM_SUDOERS_USER $SYSTEM_SUDOERS_USER \
    && sed -i -e "s/^$DEF_UNIX_USER/$UNIX_USER/g" $SYSTEM_SUDOERS_USER \
    && chmod 440 $SYSTEM_SUDOERS_USER
}

# Hack system
do_system_hack ()
{
  uname_r=$(uname -r)
  sfiles=""
  for sdir in $CONFIG_SYSTEM_DIR $CORE_SYSTEM_DIR
  do
    tdir=""
    [ -d $sdir/etc ] && tdir="$tdir $sdir/etc"
    [ -d $sdir/usr ] && tdir="$tdir $sdir/usr"
    [ -d $sdir/lib/modules/$uname_r ] && mdir=$sdir/lib/modules/$uname_r && tdir="$tdir $mdir"
    [ -z "$tdir" ] && continue

    for sfile in $(find $tdir -type f 2>/dev/null | grep -v /home/ | sed -e "s%$sdir%%g")
    do
      # Use left instead of right, if already in left side, ignore the others
      _sfile=$(echo $sfile | tr -s '/')
      echo "$sfiles" | grep -q ";$_sfile;"
      #[ $? -eq 0 ] && echo "duplicated: $_sfile" && continue
      [ $? -eq 0 ] && continue
      sfiles="$sfiles;$_sfile;"

      sdest=`dirname $sfile`
      [ ! -d $sdest ] && mkdir -p $sdest
      #echo "cp $sdir/$sfile $sdest"
      cp $sdir/$sfile $sdest
    done
  done

  # Fix up sudo support, make sure hack after copy setting file
  do_sudo_hack

  touch /tmp/system.hacked
}

# Hack home
do_home_hack ()
{
  # Install more system configuration files
  [ ! -d $DESKTOP_PATH ] && mkdir $DESKTOP_PATH

  # Override user's configurations pre-installed in /usr/share/desktop/home/
  ROOT_SYSTEM_DIR=/usr/share/desktop/
  hfiles=""

  # If not belong our desktop, ignore them
  dfilters="INIT_FILTER"
  if [ "$desktop" != "lxqt" ]; then
    dfilters="$dfilters|lxqt|pcmanfm-qt"
  fi
  if [ "$desktop" != "xfce4" ]; then
    dfilters="$dfilters|xfce"
  fi

  for hdir in $CONFIG_SYSTEM_DIR $CORE_SYSTEM_DIR $ROOT_SYSTEM_DIR
  do
    [ ! -d $hdir/home ] && continue

    for hfile in `find $hdir/home -type f | sed -e "s%$hdir%%g" | grep -E -v "$dfilters"`
    do
      # Use left instead of right, if already in left side, ignore the others
      # the old path: /usr/share/desktop/home/.config has no user info, should support it
      _hfile=$(echo $hfile | sed -e "s%$DEF_HOME/%/home/%g" | tr -s '/')
      echo "$hfiles" | grep -q ";$_hfile;"
      #[ $? -eq 0 ] && echo "duplicated: $_hfile" && continue
      [ $? -eq 0 ] && continue
      hfiles="$hfiles;$_hfile;"

      _hfile=$(echo $_hfile | sed -e "s%/home/%$HOME/%g")
      hdest=`dirname $_hfile`
      # Ignore if already there
      [ -f $_hfile ] && continue

      # do copy it
      [ ! -d $hdest ] && mkdir -p $hdest
      #echo "cp $hdir/$hfile $hdest"
      cp $hdir/$hfile $hdest
    done
  done

  # Clean up lxqt & xfce specific files
  [ "$desktop" != "lxqt" ] && rm -rf $HOME/.config/lxqt $HOME/.config/pcmanfm-qt $HOME/.config/autostart/lxqt*.desktop &
  [ "$desktop" != "xfce4" ] && rm -rf $HOME/.config/xfce4 $HOME/.config/autostart/xfce*.desktop &

  # update owner of $HOME
  chown $UNIX_USER:$UNIX_USER -R $HOME/

  touch /tmp/home.hacked
}

# Don't touch me
[ -z "$LAB_SECURITY" ] && LAB_SECURITY=0
do_unlock
get_vars UNIX_USER UNIX_UID
[ "x$UNIX_UID" = "x0" ] && UNIX_UID=1000

# Prepare network and mirror site
do_prepare &

# create a ubuntu user
DEF_HOME=/home/$DEF_UNIX_USER
HOME=/home/$UNIX_USER
DESKTOP_PATH=$HOME/Desktop/
CREATE_FLAG=/create_flag

if [ -f $CREATE_FLAG ]; then
  # Simply report current setting
  get_vars UNIX_PWD VNC_PWD VNC_PWD_VIEWONLY
  echo "User: $UNIX_USER ,Password: $UNIX_PWD ,VNC Password: $VNC_PWD ,Viewonly Password: $VNC_PWD_VIEWONLY"
else
  # !home files
  do_system_hack &

  # Detect desktop
  do_desktop_config

  # Create home
  do_home_create

  # home files
  do_home_hack &

  do_user_config
fi

# update owner for the mapped volumes
do_owner_config

# configure loop devices
do_loop_config

# Report boot_completed, report earlier for better user experience
echo "boot_completed"

# Only required by first boot, still during boot
if [ ! -f $CREATE_FLAG ]; then
  # Wait for operations finish
  i=0
  while :;
  do
    sleep 1
    [ -f /tmp/home.hacked -a -f /tmp/system.hacked ] && break
  done
  rm -rf /tmp/{home.hacked,system.hacked} &

  # Touch a flag
  touch $CREATE_FLAG
fi

# Disable rsyslog and fail2ban
sshd_conf=/etc/supervisor/conf.d/sshd.conf
if [ "x$LAB_SECURITY" = "x0" ]; then
  sed -i -e "/rsyslog/,/redirect_stderr/d" $sshd_conf
  sed -i -e "/fail2ban/,/redirect_stderr/d" $sshd_conf
fi

# VNC setting, should wait for /tmp/system.hacked
do_vnc_config

# Run image built-in tasks
run_startup_scripts

# Reset environment passed from host
if [ -n "$VARS" ]; then
  VARS="$(echo $VARS | sed -e 's/\(HOST_OS\|UNIX_USER\|UNIX_UID\)//g')"
  unset $VARS
fi

# Launch supervisor tasks
SYSTEM_SUPERVISORD_CONF=/etc/supervisor/supervisord.conf
/usr/bin/supervisord -n -c $SYSTEM_SUPERVISORD_CONF
